<!DOCTYPE html>
<html>
<head>
  <title>Electric Potential vs. Position Graph</title>
  <style>
    body {
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100vh;
      margin: 0;
    }
    canvas {
      border: 1px solid #ccc;
    }
  </style>
</head>
<body>
  <canvas id="physics-graph" width="600" height="450"></canvas>
  <script>
    const canvas = document.getElementById('physics-graph');
    const ctx = canvas.getContext('2d');

    // --- Configuration ---
    const originX = 320;
    const originY = 220;
    const scaleX = 30;
    const scaleY = 10;
    const axisColor = '#333';
    const gridColor = '#ddd';
    const graphColor = 'black';
    const labelColor = 'black';
    const dashedColor = 'gray';

    // --- Transformation Functions ---
    function toCanvasX(x) {
      return originX + x * scaleX;
    }
    function toCanvasY(v) {
      return originY - v * scaleY;
    }

    // --- Main Drawing Function ---
    function draw() {
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      drawAxes();
      drawTicksAndLabels();
      drawDashedLines();
      drawGraph();
      drawPointLabels();
      drawTitle();
    }

    // --- Component Drawing Functions ---

    function drawAxes() {
      ctx.strokeStyle = axisColor;
      ctx.lineWidth = 1.5;

      // X-axis
      ctx.beginPath();
      ctx.moveTo(20, originY);
      ctx.lineTo(canvas.width - 20, originY);
      ctx.stroke();
      // Arrow
      ctx.beginPath();
      ctx.moveTo(canvas.width - 20, originY);
      ctx.lineTo(canvas.width - 30, originY - 5);
      ctx.moveTo(canvas.width - 20, originY);
      ctx.lineTo(canvas.width - 30, originY + 5);
      ctx.stroke();

      // Y-axis
      ctx.beginPath();
      ctx.moveTo(originX, canvas.height - 20);
      ctx.lineTo(originX, 20);
      ctx.stroke();
      // Arrow
      ctx.beginPath();
      ctx.moveTo(originX, 20);
      ctx.lineTo(originX - 5, 30);
      ctx.moveTo(originX, 20);
      ctx.lineTo(originX + 5, 30);
      ctx.stroke();
    }

    function drawTicksAndLabels() {
      ctx.fillStyle = labelColor;
      ctx.strokeStyle = axisColor;
      ctx.lineWidth = 1;
      ctx.font = '14px Arial';

      // X-axis ticks and labels
      ctx.textAlign = 'center';
      ctx.textBaseline = 'top';
      for (let x = -8; x <= 9; x++) {
        if (x !== 0) {
          const cx = toCanvasX(x);
          ctx.beginPath();
          ctx.moveTo(cx, originY);
          ctx.lineTo(cx, originY + 5);
          ctx.stroke();
          if (x === -5 || x === 5) {
            ctx.fillText(x.toString(), cx, originY + 8);
          }
        }
      }
      ctx.fillText('O', originX - 8, originY + 8);
      ctx.fillText('x/m', canvas.width - 30, originY + 10);

      // Y-axis ticks and labels
      ctx.textAlign = 'right';
      ctx.textBaseline = 'middle';
      const yValues = [-12, -6, 6, 12];
      for (const v of yValues) {
        const cy = toCanvasY(v);
        ctx.beginPath();
        ctx.moveTo(originX, cy);
        ctx.lineTo(originX - 5, cy);
        ctx.stroke();
        ctx.fillText(v.toString(), originX - 8, cy);
      }
      ctx.textAlign = 'center';
      ctx.fillText('V/V', originX, 10);
    }

    function drawDashedLines() {
        ctx.strokeStyle = dashedColor;
        ctx.lineWidth = 1;
        ctx.setLineDash([4, 3]);

        // from b to x-axis
        ctx.beginPath();
        ctx.moveTo(toCanvasX(-5), toCanvasY(12));
        ctx.lineTo(toCanvasX(-5), toCanvasY(0));
        ctx.stroke();
        
        // from c to x-axis
        ctx.beginPath();
        ctx.moveTo(toCanvasX(-2), toCanvasY(12));
        ctx.lineTo(toCanvasX(-2), toCanvasY(0));
        ctx.stroke();

        // from e downwards
        ctx.beginPath();
        ctx.moveTo(toCanvasX(2), toCanvasY(0));
        ctx.lineTo(toCanvasX(2), toCanvasY(-6));
        ctx.stroke();
        
        // from g to x-axis
        ctx.beginPath();
        ctx.moveTo(toCanvasX(5), toCanvasY(-6));
        ctx.lineTo(toCanvasX(5), toCanvasY(0));
        ctx.stroke();
        
        ctx.setLineDash([]); // Reset line dash
    }


    function drawGraph() {
      ctx.strokeStyle = graphColor;
      ctx.lineWidth = 2;
      
      const points = [
        {x: -8, v: 0},   // Start on axis
        {x: -7, v: 0},   // a
        {x: -5, v: 12},  // b
        {x: -2, v: 12},  // c
        {x: 2, v: 0},    // e
        {x: 3, v: -6},   // f
        {x: 5, v: -6},   // g
        {x: 8, v: 0},    // h
        {x: 9, v: 0}    // End on axis
      ];

      ctx.beginPath();
      ctx.moveTo(toCanvasX(points[0].x), toCanvasY(points[0].v));
      for (let i = 1; i < points.length; i++) {
        ctx.lineTo(toCanvasX(points[i].x), toCanvasY(points[i].v));
      }
      ctx.stroke();
    }

    function drawPointLabels() {
        ctx.fillStyle = labelColor;
        ctx.font = 'italic 16px Times New Roman';
        
        ctx.fillText('a', toCanvasX(-7.3), toCanvasY(1));
        ctx.fillText('b', toCanvasX(-5.5), toCanvasY(12.5));
        ctx.fillText('c', toCanvasX(-1.8), toCanvasY(12.5));
        ctx.fillText('d', toCanvasX(0.2), toCanvasY(6.5));
        ctx.fillText('e', toCanvasX(2.2), toCanvasY(1));
        ctx.fillText('f', toCanvasX(2.8), toCanvasY(-7));
        ctx.fillText('g', toCanvasX(5.2), toCanvasY(-7));
        ctx.fillText('h', toCanvasX(8.2), toCanvasY(1));
    }

    function drawTitle() {
      ctx.fillStyle = labelColor;
      ctx.font = '16px "SimSun", "Songti SC", serif';
      ctx.textAlign = 'center';
      ctx.fillText('习题 7-33 图', canvas.width / 2, canvas.height - 30);
    }

    // --- Execute Drawing ---
    draw();

  </script>
</body>
</html>